﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;

namespace MediaStreamer.Containers
{
    public class ControlTemplate
    {
        public ControlTemplateSettings Settings { get; set; }
        public string TemplateDirectory { get; set; }
        public string Name { get; set; }
        public string Raw { get; set; }
        public string ItemRaw { get; set; }
        public string CurrentItemRaw { get; set; }
        public string ParentItemRaw { get; set; }
        public string SeperatorRaw { get; set; }

        public ControlTemplate(string controlName, string baseDir)
        {
            var controlDir = string.Format("{0}Controls{2}{1}{2}", baseDir, controlName,
                                           Path.DirectorySeparatorChar);

            Name = controlName;
            TemplateDirectory = controlDir;
            Load();
        }

        private void Load()
        {
            // Make sure basic template exist
            if (!File.Exists(TemplateDirectory + "index.html"))
                throw new ArgumentException("templateDir is not a valid PageTemplate location.");
            // Make sure template settings exist
            if (!File.Exists(TemplateDirectory + "settings.txt"))
                throw new ArgumentException("templateDir is not a valid PageTemplate location.");

            Raw = File.ReadAllText(TemplateDirectory + "index.html");
            ItemRaw = File.ReadAllText(TemplateDirectory + "item.html");

            if (File.Exists(TemplateDirectory + "currentitem.html"))
                CurrentItemRaw = File.ReadAllText(TemplateDirectory + "currentitem.html");

            if (File.Exists(TemplateDirectory + "parentitem.html"))
                ParentItemRaw = File.ReadAllText(TemplateDirectory + "parentitem.html");

            if (File.Exists(TemplateDirectory + "seperator.html"))
                SeperatorRaw = File.ReadAllText(TemplateDirectory + "seperator.html");

            ParseSettings();
        }

        private void ParseSettings()
        {
            var tempSettings = new ControlTemplateSettings();

            string[] lines = File.ReadAllLines(TemplateDirectory + "settings.txt");

            foreach (var line in lines)
            {
                var pair = line.Split(':');
                if (pair.Length != 2)
                    continue;

                var key = pair[0].ToLower();
                var value = pair[1];

                switch (key)
                {
                    case "maxdisplayitems":
                        int mDisplayItems;
                        if (int.TryParse(value, out mDisplayItems))
                        {
                            tempSettings.MaxItems = mDisplayItems;
                        }
                        break;
                }
            }

            Settings = tempSettings;
        }

        public string PopulateControl(RequestInfo requestInfo, IEnumerable<MenuItem> items)
        {
            string lowerName = Name.ToLower();
            bool hasCurrent = !string.IsNullOrEmpty(CurrentItemRaw);
            bool hasParent = !string.IsNullOrEmpty(ParentItemRaw);

            int start;
            var strStart = requestInfo.Query.Get(lowerName + "start");
            if (!int.TryParse(strStart, out start))
            {
                start = 0;
            }

            int totalCount = items.Count();

            // Insanity check, no need to render template if we have no items.
            if (totalCount == 0)
                return string.Empty;

            var maxVisibleItems = Settings.MaxItems;

            int index = 1;

            int lastIndex = start + Settings.MaxItems;
            if (lastIndex > (start + totalCount))
            {
                lastIndex = start - totalCount;
            }

            // Only take the number of items we are interested in
            IEnumerable<MenuItem> filteredItems = start == 0 ? items.Take(Settings.MaxItems) : items.Skip(start).Take(Settings.MaxItems);

            StringBuilder sbItems = new StringBuilder();
            foreach (var menuItem in filteredItems)
            {
                StringBuilder sbItem;
                if (hasCurrent && requestInfo.IsEqual(menuItem.NavigateToLocation))
                {
                    sbItem = new StringBuilder(CurrentItemRaw);
                }
                else if (hasParent && requestInfo.ResourceId.StartsWith(menuItem.NavigateToLocation))
                {
                    sbItem = new StringBuilder(ParentItemRaw);
                }
                else
                {
                    sbItem = new StringBuilder(ItemRaw);
                }

                sbItem.Replace("{INDEX}", (index + start).ToString());
                sbItem.Replace("{INDEX:2}", string.Format("{0:00}", (index + start)));
                sbItem.Replace("{TEXT}", menuItem.Text);
                sbItem.Replace("{NavigationUrl}", menuItem.NavigateToLocation);

                if (index == 1)
                {
                    // load previous items if we use "UP" key on first item.
                    sbItem.Replace("{EXTRAATTRIBUTES}", "ONKEYUPSET=\"prev\"");
                }
                else if (index == lastIndex)
                {
                    // load next items if we use "DOWN" key on last item.
                    sbItem.Replace("{EXTRAATTRIBUTES}", "ONKEYDOWNSET=\"next\"");

                    // We want to be able to add seperator between items
                    if (!string.IsNullOrEmpty(SeperatorRaw))
                    {
                        sbItem.Replace("{SEPERATOR}", SeperatorRaw);
                    }
                }
                else
                {
                    // If not first or last item, remove the attribute
                    sbItem.Replace("{EXTRAATTRIBUTES}", string.Empty);

                    // We want to be able to add seperator between items
                    if (!string.IsNullOrEmpty(SeperatorRaw))
                    {
                        sbItem.Replace("{SEPERATOR}", SeperatorRaw);
                    }
                }

                // We are begining on number 1, so we need to look for odd numbers to show even..
                if (index % 2 != 0)
                {
                    sbItem.Replace("{EVEN}", "even");
                    sbItem.Replace("{ODD}", string.Empty);
                }
                else
                {
                    sbItem.Replace("{EVEN}", string.Empty);
                    sbItem.Replace("{ODD}", "odd");
                }
                sbItems.Append(sbItem);

                index++;
            }
            // ignore last increase of index.
            index -= 1;

            StringBuilder content = new StringBuilder(Raw);

            content.Replace("{ITEMS}", sbItems.ToString());
            content.Replace("{START}", (start + 1).ToString());
            content.Replace("{COUNT}", (index + start).ToString());

            content.Replace("{TOTALCOUNT}", totalCount.ToString());

            bool hasPrev = start > 0;
            bool hasNext = (start + maxVisibleItems) < totalCount;

            content.Replace("{PREVICON}", hasPrev ? "on" : "off");
            content.Replace("{NEXTICON}", hasNext ? "on" : "off");

            string nextOrPrevPageQueryKey = lowerName + "start";
            if (totalCount > maxVisibleItems)
            {

                if ((start + maxVisibleItems) < totalCount)
                {

                    var nextPageParams = new NameValueCollection { { nextOrPrevPageQueryKey, (index + start).ToString() } };
                    nextPageParams = requestInfo.Query.UpdateWithCollection(nextPageParams);
                    content.Replace("{NEXTPAGE}", nextPageParams.AsString());
                    //content.Replace("{NEXTPAGE}", "?{LOWERNAME}start=" + (index + start));
                }
                else if ((start + maxVisibleItems) >= totalCount)
                {
                    // We don't need todo anything here because if we don't, the start index will be set to 0.
                }
                else
                {
                    //content.Replace("{NEXTPAGE}", "?{LOWERNAME}start=" + (totalCount - maxVisibleItems));
                    var nextPageParams = new NameValueCollection { { nextOrPrevPageQueryKey, (totalCount - maxVisibleItems).ToString() } };
                    nextPageParams = requestInfo.Query.UpdateWithCollection(nextPageParams);
                    content.Replace("{NEXTPAGE}", nextPageParams.AsString());
                }
            }

            if (totalCount > maxVisibleItems)
            {
                if (start == 0)
                {
                    //content.Replace("{PREVPAGE}", "?{LOWERNAME}start=" + (totalCount - Settings.MaxItems));
                    var prevPageParams = new NameValueCollection { { nextOrPrevPageQueryKey, (totalCount - Settings.MaxItems).ToString() } };
                    prevPageParams = requestInfo.Query.UpdateWithCollection(prevPageParams);
                    content.Replace("{PREVPAGE}", prevPageParams.AsString());
                }
                if ((start - maxVisibleItems) > 0)
                {
                    //content.Replace("{PREVPAGE}", "?{LOWERNAME}start=" + (start - Settings.MaxItems));
                    var prevPageParams = new NameValueCollection { { nextOrPrevPageQueryKey, (start - Settings.MaxItems).ToString() } };
                    prevPageParams = requestInfo.Query.UpdateWithCollection(prevPageParams);
                    content.Replace("{PREVPAGE}", prevPageParams.AsString());
                }
            }

            var nextOrPrevPageParams = new NameValueCollection { { nextOrPrevPageQueryKey, (0).ToString() } };
            nextOrPrevPageParams = requestInfo.Query.UpdateWithCollection(nextOrPrevPageParams);

            // If we havn't replaced PREVPAGE yet, set it to same page.
            //content.Replace("{PREVPAGE}", "?{LOWERNAME}start=" + 0);
            content.Replace("{PREVPAGE}", nextOrPrevPageParams.AsString());
            // If we havn't replaced NEXTPAGE yet, set it to same page.
            //content.Replace("{NEXTPAGE}", "?{LOWERNAME}start=" + 0);
            content.Replace("{NEXTPAGE}", nextOrPrevPageParams.AsString());

            content.Replace("{SEPERATOR}", string.Empty);

            // This has to be last
            content.Replace("{LOWERNAME}", lowerName);

            return content.ToString();
        }
    }
}
